/*
 * Copyright (C) 2010 mAPPn.Inc
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.mol.market.ui_v4;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.Html;
import android.text.TextUtils;
import android.view.*;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.widget.*;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
import com.actionbarsherlock.app.SherlockFragment;
import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.mol.market.Constants;
import com.mol.market.R;
import com.mol.market.Session;
import com.mol.market.common.util.DBUtils;
import com.mol.market.common.util.Utils;
import com.mol.market.common.vo.UpgradeInfo;
import com.mol.market.common.widget.AppListAdapter;
import com.mol.market.common.widget.LoadingDrawable;

import java.text.Collator;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 已安装应用管理页
 * 
 * @author andrew
 * @date 2011-11-4
 * @since Version 0.8.3
 */
public class AppsUpdateFragment extends SherlockFragment implements Observer, OnItemClickListener {

    private final static int CONTEXT_MENU_DELETE_FILE = 0;
    private final static int CONTEXT_MENU_IGNORE_UPDATE = 1;
    
    /* package */ListView mList;
    private FrameLayout mLoading;
    private ProgressBar mProgress;

    private Session mSession;
    private SherlockFragmentActivity mActivity;
    private AppListAdapter mAdapter;
    private int mLongClickPos;
    private TextView mTitle;
    private TextView updateNum;
    private View mUpdateAllView;
    private int mCount;

    private static Comparator<HashMap<String, Object>> sComparator =
        
        new Comparator<HashMap<String, Object>>() {
        /*
         * +-------------- 
         * + 可更新产品 
         * + (音序排序) 
         * +-------------- 
         * + 已经安装产品 
         * + (音序排序)
         * +--------------
         */
        @Override
        public int compare(HashMap<String, Object> paramT1, HashMap<String, Object> paramT2) {

            boolean isUpdate1 = (Boolean) paramT1.get(Constants.KEY_PRODUCT_IS_UPGRADE);
            boolean isUpdate2 = (Boolean) paramT2.get(Constants.KEY_PRODUCT_IS_UPGRADE);

            if (isUpdate1 && !isUpdate2) {
                return -1;
            } else if (isUpdate2 && !isUpdate1) {
                return 1;
            } else {
                String name1 = String.valueOf(paramT1.get(Constants.KEY_PRODUCT_NAME));
                String name2 = String.valueOf(paramT2.get(Constants.KEY_PRODUCT_NAME));
                return Collator.getInstance(Locale.CHINESE).compare(name1, name2);
            }
        }
    };
    

    private BroadcastReceiver mInstallReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {

            final String action = intent.getAction();
            final String packageName = intent.getData().getSchemeSpecificPart();

            if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
                mAdapter.addData(getApkInfo(mActivity, packageName));
                updateTitle(mAdapter.getCount());
            } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
                mAdapter.removeDataWithPackageName(packageName);
                updateTitle(mAdapter.getCount());
            } 
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_PACKAGE_ADDED);
        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
        filter.addDataScheme("package");

        // 接受更新提醒
        mActivity = getSherlockActivity();
        mActivity.registerReceiver(mInstallReceiver, filter);
        mSession = Session.get(mActivity);
        mSession.addObserver(this);
        new LoadAppTask().execute();
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();
        mActivity.unregisterReceiver(mInstallReceiver);
        mAdapter = null;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View root = inflater.inflate(R.layout.activity_apps_manager_layout, container, false);
        doInitView(root);
        return root;
    }

    public boolean doInitView(View root) {

        mLoading = (FrameLayout) root.findViewById(R.id.loading);
        mProgress = (ProgressBar) mLoading.findViewById(R.id.progressbar);
        mProgress.setIndeterminateDrawable(new LoadingDrawable(mActivity));
        mProgress.setVisibility(View.VISIBLE);
        mList = (ListView) root.findViewById(android.R.id.list);
        mList.setEmptyView(mLoading);
        mList.setOnItemClickListener(this);
        mList.setItemsCanFocus(true);
        mAdapter = doInitListAdapter();
        mList.addHeaderView(createUpdateAllView(), null, false);
        mList.setAdapter(mAdapter);
        registerForContextMenu(mList);
        return true;
    }

    public AppListAdapter doInitListAdapter() {
        mAdapter = new AppListAdapter(mActivity,
                null,
                R.layout.activity_apps_manager_installed_item, 
                new String[] { 
                    Constants.KEY_PRODUCT_ICON_URL_LDPI,
                    Constants.KEY_PRODUCT_NAME, 
                    Constants.KEY_PRODUCT_VERSION_NAME, 
                    Constants.KEY_PRODUCT_NEW_VERSION_NAME,
                    Constants.KEY_PRODUCT_DOWNLOAD }, 
                new int[] { 
                    R.id.iv_logo, 
                    R.id.tv_name,
                    R.id.tv_current_version, 
                    R.id.tv_update_version,
                    R.id.tv_operation });
        mAdapter.setProductList();
        mAdapter.setNeedSort(sComparator);
        mAdapter.setActivity(mActivity);
        return mAdapter;
    }

    @SuppressWarnings("unchecked")
    @Override
    public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
        
        // 去产品详细页
        HashMap<String, Object> item = (HashMap<String, Object>) mAdapter.getItem(arg2
                - mList.getHeaderViewsCount());
        
        if (item == null) {
            return;
        }
        String pkgName = (String) item.get(Constants.KEY_PRODUCT_PACKAGE_NAME);
        Intent detailIntent = new Intent(mActivity, ProductDetailActivity.class);
        detailIntent.putExtra(Constants.EXTRA_PACKAGE_NAME, pkgName);
        detailIntent.putExtra(Constants.EXTRA_PRODUCT_NAME,
                (String) item.get(Constants.KEY_PRODUCT_NAME));
        detailIntent.putExtra(Constants.EXTRA_SOURCE_TYPE,
                (String) item.get(Constants.KEY_PRODUCT_SOURCE_TYPE));
        startActivity(detailIntent);
        Utils.trackEvent(mActivity, Constants.GROUP_7, 
                Constants.CLICK_DETAIL);
    }

    @SuppressWarnings("unchecked")
    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
        AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo;
        mLongClickPos = acmi.position - mList.getHeaderViewsCount();
        HashMap<String, Object> item = (HashMap<String, Object>) mAdapter.getItem(mLongClickPos);
        boolean isUpdate = (Boolean) item.get(Constants.KEY_PRODUCT_IS_UPGRADE);

        if (isUpdate) {
            menu.add(0, CONTEXT_MENU_IGNORE_UPDATE, 0, R.string.ignore_update);
            menu.add(0, CONTEXT_MENU_DELETE_FILE, 0, R.string.operation_uninstall);
        }
    }
    
    @Override
    public boolean onContextItemSelected(MenuItem item) {

        if (item.getGroupId() != 0) {
            return false;
        }

        switch (item.getItemId()) {
        case CONTEXT_MENU_DELETE_FILE:
            uninstall(mLongClickPos);
            break;
            
        case CONTEXT_MENU_IGNORE_UPDATE:
            ignoreUpgrade(mLongClickPos);
            break;
            
        default:
            return super.onContextItemSelected(item);
        }
        return true;
    }
    
    /*
     * 忽略当前版本的更新
     */
    @SuppressWarnings("unchecked")
    private void ignoreUpgrade(int pos) {
        HashMap<String, Object> item = (HashMap<String, Object>) mAdapter.getItem(pos);
        String packageName = (String) item.get(Constants.KEY_PRODUCT_PACKAGE_NAME);
        item.put(Constants.KEY_PRODUCT_NEW_VERSION_NAME, "");
        item.put(Constants.KEY_PRODUCT_IS_UPGRADE, false);
        DBUtils.ignoreUpdate(mActivity, packageName);
        mAdapter.sort();
    }
    
    /*
     * 卸载当前应用
     */
    @SuppressWarnings("unchecked")
    private void uninstall(int pos) {
        HashMap<String, Object> item = (HashMap<String, Object>) mAdapter.getItem(pos);
        String packageName = (String) item.get(Constants.KEY_PRODUCT_PACKAGE_NAME);
        Utils.uninstallApk(mActivity, packageName);
    }

    /*
     * 更新应用数
     */
    private void updateTitle(int appCounter) {
        if (mTitle != null) {
			String str = appCounter + "";
			mTitle.setText(Html.fromHtml(getString(R.string.all_apps,
					"<font color=\"#FFB400\">" + str + "</font>")));
		}
	}
    
    /*
     * 全部更新按钮
     */
    private Button mUpdateAll;
    
    /*
     * 创建更新全部项目（HeaderView）
     */
    private View createUpdateAllView() {

        mUpdateAllView = mActivity.getLayoutInflater().inflate(
                R.layout.activity_apps_manager_update_all_item, mList, false);
        mUpdateAllView.setLongClickable(true);
        mUpdateAllView.setOnLongClickListener(new OnLongClickListener() {
			
			@Override
			public boolean onLongClick(View v) {
				mList.removeHeaderView(mUpdateAllView);
				return true;
			}
		});
        mTitle = (TextView) mUpdateAllView.findViewById(R.id.tv_apps_num);
        updateNum = (TextView) mUpdateAllView.findViewById(R.id.tv_update_num);
        int number = mSession.getUpgradeNumber();
        if (number < 0) {
            number = 0;
        }
        updateNum.setText(Html.fromHtml(getString(R.string.has_update, "<font color=\"#78b400\">" + number + "</font>")));

        mUpdateAll = (Button) mUpdateAllView.findViewById(R.id.btn_update_all);
        mUpdateAll.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // 全部更新
                Utils.trackEvent(mActivity, Constants.GROUP_7, 
                        Constants.CLICK_UPDATE_ALL);
                mAdapter.updateAll();
                mUpdateAll.setVisibility(View.GONE);
            }
        });

        if (number > 1) {
            mUpdateAll.setVisibility(View.VISIBLE);
        } else {
            mUpdateAll.setVisibility(View.GONE);
        }
        return mUpdateAllView;
    }
    
    /*
     * 获取单个应用的信息
     */

    private static HashMap<String, Object> getApkInfo(Context context, String packageName) {
        final PackageManager pm = context.getPackageManager();
        try {
            PackageInfo info = pm.getPackageInfo(packageName, 0);
            HashMap<String, Object> application = new HashMap<String, Object>();
            application.put(Constants.KEY_PRODUCT_PACKAGE_NAME, info.packageName);
            application.put(Constants.KEY_PRODUCT_ICON_URL, packageName);
            application.put(Constants.KEY_PRODUCT_NAME, info.applicationInfo.loadLabel(pm));
            application.put(Constants.KEY_PRODUCT_VERSION_NAME,
                    context.getString(R.string.current_version, info.versionName));
            application.put(Constants.KEY_PRODUCT_ICON_URL_LDPI, info);
            application.put(Constants.KEY_PRODUCT_NEW_VERSION_NAME, "");
            application.put(Constants.KEY_PRODUCT_IS_UPGRADE, false);
            return application;
        } catch (NameNotFoundException e) {
            Utils.E("getApkInfo NameNotFoundException for " + packageName, e);
        }
        return null;
    }

    /**
     * 加载所有已经安装的应用
     *
     */
    private class LoadAppTask extends AsyncTask<Void, Void, ArrayList<HashMap<String, Object>>> {

        private int mUpdateCounter;

        @Override
        protected ArrayList<HashMap<String, Object>> doInBackground(Void... params) {

            final Context context = mActivity;

            final PackageManager pm = mActivity.getPackageManager();
            
            ArrayList<HashMap<String, Object>> data = null;
            synchronized (mSession.mPreloadInstalled) {
                data = new ArrayList<HashMap<String, Object>>(mSession.mPreloadInstalled.values());

                if (data == null || data.size() == 0) {
                    data = new ArrayList<HashMap<String, Object>>();
                    List<PackageInfo> apps = mSession.getInstalledAppsInfo();

                    for (PackageInfo info : apps) {
                        HashMap<String, Object> item = new HashMap<String, Object>();
                        item.put(Constants.KEY_PRODUCT_PACKAGE_NAME, info.packageName);
                        item.put(Constants.KEY_PRODUCT_ICON_URL_LDPI, info);
                        item.put(Constants.KEY_PRODUCT_NAME, info.applicationInfo.loadLabel(pm));
                        item.put(Constants.KEY_PRODUCT_VERSION_NAME,
                                context.getString(R.string.current_version, info.versionName));
                        data.add(item);
                    }
                }

                final ConcurrentHashMap<String, UpgradeInfo> update = mSession.getUpdateList();
                mUpdateCounter = 0;
                for (HashMap<String, Object> info : data) {

                    String pkgName = (String) info.get(Constants.KEY_PRODUCT_PACKAGE_NAME);
                    if (update.containsKey(pkgName)) {

                        // 可更新产品
                        UpgradeInfo upgradeInfo = update.get(pkgName);
                        info.put(Constants.KEY_PRODUCT_ID, upgradeInfo.pid);
                        info.put(Constants.KEY_PRODUCT_ICON_URL, pkgName);
                        info.put(Constants.KEY_PRODUCT_NEW_VERSION_NAME,
                                context.getString(R.string.new_version, upgradeInfo.versionName));
                        info.put(Constants.KEY_PRODUCT_IS_UPGRADE, true);
                        info.put(Constants.KEY_PRODUCT_SOURCE_TYPE, upgradeInfo.sourceType);

                        if (TextUtils.isEmpty(upgradeInfo.filePath)) {
                            mUpdateCounter++;
                        }

                    } else {
                        info.put(Constants.KEY_PRODUCT_IS_UPGRADE, false);
                    }
                }
            }
            return data;
        }

        @Override
        protected void onPostExecute(ArrayList<HashMap<String, Object>> result) {
            if (mAdapter != null) {
                mAdapter.addDataList(result);
                if (mUpdateCounter > 1) {
                    mUpdateAll.setVisibility(View.VISIBLE);
                } else {
                    mUpdateAll.setVisibility(View.GONE);
                }
                updateTitle(result.size());
            }
        }
    }

    @Override
    public void update(Observable observable, Object data) {
        if (isResumed() && data instanceof Integer) {
            if (Constants.INFO_UPDATE == (Integer) data) {
                // 刷新可更新应用数
                int counter = mSession.getUpgradeNumber();
                if (counter >= 0 && counter != mCount) {
					mCount = counter;
					updateNum.setText(Html.fromHtml(getString(
							R.string.has_update, "<font color=\"#78b400\">"
									+ counter + "</font>")));
				} else if (counter <= 1) {
					mUpdateAll.setVisibility(View.GONE);
                }
            }
        }
    }
}
